﻿using System;
using System.Collections.Generic;
using FluentNH_DO.Contract;
using FluentNH_DO.Entities;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using NHibernate;
using NHibernate.ByteCode.Castle;
using NHibernate.Cfg;
using NHibernate.Criterion;
using NHibernate.Tool.hbm2ddl;
using NHibernate.LambdaExtensions;
using Lucene.Net.Index;
using Lucene.Net.Store;
using Lucene.Net.Analysis;
using Lucene.Net.Analysis.Standard;



namespace FluentNH_DAL
{
    public class DataProvider : IContact
    {
        #region Private
        private static ISessionFactory _sessionObject;
        private static IndexWriter _indexWriter;
        private static StandardAnalyzer analyzer = new StandardAnalyzer();

        private static ISessionFactory CreateSessionFactory()
        {
            return Fluently.Configure()
                .Database(MsSqlConfiguration.MsSql2005
                .ConnectionString(c => c
                .Server("mssql01.webhuset.no")
                .Database("cafebabe")
                .Username("cafebabe")
                .Password("vFIsIZu0y"))
                .ProxyFactoryFactory(typeof(ProxyFactoryFactory)))
                .Mappings(m => m.FluentMappings.AddFromAssemblyOf<DataProvider>())
                .ExposeConfiguration(BuildSchema)
                //.ExposeConfiguration(cfg =>
                //    {
                //        cfg.SetListener(NHibernate.Event.ListenerType.PostInsert, new FullTextIndexEventListener());
                //    })
                .BuildSessionFactory();
        }

        private static void BuildSchema(Configuration config)
        {
            // this NHibernate tool takes a configuration (with mapping info in)
            // and exports a database schema from it
            new SchemaExport(config)
                .Create(true, false);
            // 1st parameter - Show DDL (Data Definition Language) in consolet)
            // 2nd parameter - Run DDL mot databasen(Make tables and relations according to mapping).
        }

        private static ISessionFactory GetSessionObject()
        {
            if (_sessionObject == null)
            {
                _sessionObject = CreateSessionFactory();
                //Contact contact = new Contact {Name = "Test Contact"};

            }
            return _sessionObject;
        }

        private static IndexWriter GetIndexWriter()
        {
            if (_indexWriter == null)
            {

                //TextFileIndexer index = new TextFileIndexer();

                //_indexWriter = new IndexWriter(index, analyzer, true);
            }
            return _indexWriter;
        }

        #endregion
        
        #region Implementation of IContact

        public Contact GetContactById(int id)
        {
            using (var session = GetSessionObject().OpenSession())
            {
                return session.Get<Contact>(id);
            }
        }

        public IList<Contact> GetContactByName(string name)
        {
            using (var session = GetSessionObject().OpenSession())
            {
                 var contacts = session.CreateCriteria(typeof (Contact))
                     .Add(SqlExpression.Like<Contact>(c => c.Name, name, MatchMode.Anywhere ))
                    .List<Contact>();

                return contacts;
            }
        }

        public IList<Contact> GetContacts()
        {
            using (var session = GetSessionObject().OpenSession())
            {
                ICriteria criteria = session.CreateCriteria(typeof(Contact));
                var contacts = criteria.List<Contact>();

                return contacts;
            }
        }

        public IList<ContactInfo> GetContactInfo(Contact contact)
        {
            using (var session = GetSessionObject().OpenSession())
            {
                //DetachedCriteria subquery = DetachedCriteria.For<Contact>()
                //    .Add(Projections. Property("LinkId"))
                //    .Add(Restrictions.Eq("Name", "Attrib1"))
                //    .Add(Restrictions.Eq("Type", typeof(Account)));
                //ICriteria criteria = session.CreateCriteria(typeof (ContactInfo))
                //    .Add(
                //var informations = criteria.List<ContactInfo>();
                //return (List<ContactInfo>) informations;

                throw new NotImplementedException();
            }
        }

        public ContactInfoType GetContactInfoTypeById(int id)
        {
            using (var session = GetSessionObject().OpenSession())
            {
                return session.Get<ContactInfoType>(id);
            }
        }

        public IList<ContactInfoType> GetContactInfoTypes()
        {
            throw new NotImplementedException();
        }

        public int AddContact(Contact contact)
        {
            using (var session = GetSessionObject().OpenSession())
            {
                using (var transaction = session.BeginTransaction())
                {
                    try
                    {
                        var result = (int)session.Save(contact);
                        transaction.Commit();
                        return result;
                    }
                    catch (NHibernate.HibernateException)
                    {
                        transaction.Rollback();
                        throw;
                    }
                }
            }
        }

        public int AddInfo(ContactInfo info)
        {
            using (var session = GetSessionObject().OpenSession())
            {
                using (var transaction = session.BeginTransaction())
                {
                    try
                    {
                        var result = (int)session.Save(info);
                        transaction.Commit();
                        return result;
                    }
                    catch (NHibernate.HibernateException)
                    {
                        transaction.Rollback();
                        throw;
                    }
                }
            }
        }

        public int AddType(ContactInfoType type)
        {
            using (var session = GetSessionObject().OpenSession())
            {
                using (var transaction = session.BeginTransaction())
                {
                    try
                    {
                        var result = (int)session.Save(type);
                        transaction.Commit();
                        return result;
                    }
                    catch (NHibernate.HibernateException)
                    {
                        transaction.Rollback();
                        throw;
                    }
                }
            }
        }

        public void DeleteContact(Contact contact)
        {
            throw new NotImplementedException();
        }

        public void DeleteInfo(ContactInfo info)
        {
            throw new NotImplementedException();
        }

        public void DeleteType(ContactInfoType type)
        {
            throw new NotImplementedException();
        }

        #endregion

        #region Listeners
        

        #endregion

    }
}